package com.big.gateway.filter;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.text.AntPathMatcher;
import com.big.common.core.result.ResultCode;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * <p>
 * 网关全局鉴权拦截器，用于验证用户身份和权限，保护受保护的资源
 * </p>
 *
 * @author 山归岿
 * @create 2025-06-15-19:42
 */
@Configuration
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    private final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
    // 排除鉴权的路径
    private static final String[] EXCLUDE_PATHS = {
            // 认证服务相关接口
            "/big-auth/**",
            "/test/**",
            // 网关管理接口
            "/gateway/**",

            // OpenAPI/Swagger 文档相关路径
            "/swagger-ui/**",
            // OpenAPI 3.0 接口定义路径
            "/v3/api-docs/**",
            // Swagger UI 配置路径
            "/v3/api-docs/swagger-config",
            // Swagger 资源路径
            "/swagger-resources/**",

            // Knife4j 文档界面相关路径
            // Knife4j 主页路径
            "/doc.html",
            // Knife4j 接口文档路径
            "/doc/**",
            // Knife4j 网关路由支持
            "/knife4j/**",
            // 静态资源路径
            // Knife4j 所需的 WebJars 静态资源
            "/webjars/**"
    };


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().value();

        // 检查排除路径
        for (String excludePath : EXCLUDE_PATHS) {
            if (PATH_MATCHER.match(excludePath, path)) {
                return chain.filter(exchange);
            }
        }

        // 支持任意前缀的 v3/api-docs
        if (path.contains("/v3/api-docs")) {
            return chain.filter(exchange);
        }

        // Sa-Token 登录校验
        try {
            String token = exchange.getRequest().getHeaders().getFirst("Authorization");
            if (token != null && token.startsWith("Bearer ")) {
                token = token.substring(7);
            }

            if (StpUtil.getLoginIdByToken(token) != null) {
                return chain.filter(exchange);
            }

            // Token 无效情况
            return createErrorResponse(exchange, ResultCode.UNAUTHORIZED);
        } catch (Exception e) {
            // Token 验证失败
            return createErrorResponse(exchange, ResultCode.TOKEN_ERROR);
        }
    }

    // 创建错误响应的方法
    private Mono<Void> createErrorResponse(ServerWebExchange exchange, ResultCode resultCode) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.valueOf(resultCode.getCode()));
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        String errorJson = String.format(
                "{\"code\": %d, \"message\": \"%s\"}",
                resultCode.getCode(),
                resultCode.getMessage()
        );

        DataBuffer buffer = response.bufferFactory().wrap(
                errorJson.getBytes(StandardCharsets.UTF_8)
        );

        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        // 高优先级
        return -100;
    }
}